/*
	This file is part of AVRCppLib.

    AVRCppLib is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AVRCppLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AVRCppLib.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) Maxime Lemonnier 2007-2011
 */

#ifndef MemoryLoggingTest_H_
#define MemoryLoggingTest_H_

#include "TestCase.h"
#include "Utils/Logging.h"
#include "Utils/CppExtensions.h"



class MemoryLoggingTest :  public TestCase<MemoryLoggingTest>
{
private:
	const prog_mem * testStr;

public:


	MemoryLoggingTest(const prog_mem * testMethodName, TestCase<MemoryLoggingTest>::TestMethod testMethod) :
	TestCase<MemoryLoggingTest>(testMethodName, testMethod), testStr(PROG_MEM_STRING("01234567890012345678900123456789001234567890"))
	{
	}


	bool allocateAllStack()
	{
		bool result = true;

		void * memory = alloca(distanceHeapFromStack());

		result &= !isNull(memory);

		result &= stackSize() != 0;

		return result;

	}

	bool teststackSize()
	{
		size_t initialStackSize = stackSize();

		uint8_t * memory = new(Allocators::STACK) uint8_t[45];

		bool result = AVRUNIT_ASSERT_EQUALS_LONG_TESTNAME(stackSize(), initialStackSize + 45, "stackSize() after");

		result &= AVRUNIT_ASSERT_AUTONAME(!isNull(memory));

		memory = new(Allocators::STACK)uint8_t[distanceHeapFromStack() + __malloc_margin];

		result &= AVRUNIT_ASSERT_AUTONAME(isNull(memory));

		initialStackSize = stackSize();

		result &= AVRUNIT_ASSERT_AUTONAME(allocateAllStack());

		result &= AVRUNIT_ASSERT_EQUALS_LONG_TESTNAME(stackSize(), initialStackSize, "stackSize() unchanged");

		return result;

	}


	size_t growHeap()
	{
		size_t initialHeapSize = heapSize();

		for(size_t maxNode = 1; maxNode < maxMemoryChunkLeft(); maxNode += 1)
		{
			uint8_t * memory = new uint8_t[maxNode];
			delete memory;

			if(initialHeapSize == heapSize())
				return maxNode - 1;
		}


	}

	bool testdistanceHeapFromStack()
	{
		size_t initialDistanceHeapFromStack = distanceHeapFromStack();

		uint8_t * memory = new(Allocators::STACK) uint8_t[10];

		bool result = AVRUNIT_ASSERT_AUTONAME(!isNull(memory));

		result &= AVRUNIT_ASSERT_EQUALS_LONG(distanceHeapFromStack(), initialDistanceHeapFromStack - 10);


		initialDistanceHeapFromStack = distanceHeapFromStack();

		size_t growth = growHeap();

		result &= AVRUNIT_ASSERT_IN_RANGE_LONG(distanceHeapFromStack(), initialDistanceHeapFromStack - growth, 5);


		return result;

	}


};



#endif /* MemoryLoggingTest_H_ */
